
/*
 * Copyright (c) 2006 Georgia Tech Research Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: George F. Riley<riley@ece.gatech.edu>
 *         Gustavo Carneiro <gjc@inescporto.pt>
 */

#ifndef IPV4_TEXCP_ROUTING_H
#define IPV4_TEXCP_ROUTING_H

#include <list>
#include <utility>
#include <stdint.h>
#include "ns3/ipv4-address.h"
#include "ns3/ipv4-header.h"
#include "ns3/event-garbage-collector.h"
#include "ns3/traced-callback.h"
#include "ns3/socket.h"
#include "ns3/packet.h"
#include "ns3/ptr.h"
#include "ns3/ipv4.h"
#include "ns3/timer.h"
#include "ns3/data-rate.h"
#include "ns3/ipv4-routing-protocol.h"
#include "ns3/random-variable.h"
#include "ns3/inet-socket-address.h"
#include "ipv4-texcp-table-entry.h"
#include "ipv4-flowlet-classifier.h"

#include <map>
namespace ns3 {

class Packet;
class NetDevice;
class Ipv4Interface;
class Ipv4Address;
class Ipv4MulticastRoutingTableEntry;
class Ipv4Header;
class Node;

namespace texcp_routing {

 enum SplittingMode {
    ILLEGAL,     /**< Mode not set */
    FLARE,     /**<  Use FLARE to split the traffic*/
    PREF,       /**< Use Path Re-Feedback to split the traffic */  
  };


class Ipv4TexcpTableEntry;
/**
 * \ingroup routing
 * \defgroup ipv4TexcpRouting Ipv4TexcpRouting
 */
/**
 * \ingroup ipv4TexcpRouting
 * 
 * \brief Texcp routing protocol for IP version 4 stacks.
 *
 * This class provides a basic set of methods for inserting static
 * unicast and multicast routes into the Ipv4 routing system.  
 * This particular protocol is designed to be inserted into an 
 * Ipv4ListRouting protocol but can be used also as a standalone
 * protocol.
 * 
 * The Ipv4TexcpRouting class inherits from the abstract base class 
 * Ipv4RoutingProtocol that defines the interface methods that a routing 
 * protocol must support.
 *
 * \see Ipv4RoutingProtocol
 * \see Ipv4ListRouting
 * \see Ipv4ListRouting::AddRoutingProtocol
 */
class Ipv4TexcpRouting : public Ipv4RoutingProtocol
{
public:
  static TypeId GetTypeId (void);
  static const uint32_t ROUTE_MAX = 4;

  Ipv4TexcpRouting ();
  virtual ~Ipv4TexcpRouting ();

  virtual Ptr<Ipv4Route> RouteOutput (Ptr<Packet> p, const Ipv4Header &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr);

  virtual bool RouteInput  (Ptr<const Packet> p, const Ipv4Header &header, Ptr<const NetDevice> idev,
                             UnicastForwardCallback ucb, MulticastForwardCallback mcb,
                             LocalDeliverCallback lcb, ErrorCallback ecb);

  virtual void NotifyInterfaceUp (uint32_t interface);
  virtual void NotifyInterfaceDown (uint32_t interface);
  virtual void NotifyAddAddress (uint32_t interface, Ipv4InterfaceAddress address);
  virtual void NotifyRemoveAddress (uint32_t interface, Ipv4InterfaceAddress address);
  virtual void SetIpv4 (Ptr<Ipv4> ipv4);

                                                
/**
 * \brief Check if interface is outgoing from network domain.
 *
 * \param interface Interface number
 *
 * \see Ipv4Address
 */                                              
  bool IsExternalInterface (uint32_t ifnum);
                                                                    
  Ptr<Ipv4TexcpTableEntry> AddDefaultNetworkRouteTo (Ipv4Address network, 
                                            Ipv4Mask networkMask, 
                                            uint32_t interface,
                                            Ipv4Address egressAddress);
/**
 * \brief Add a network route to the static routing table.
 *
 * \param network The Ipv4Address network for this route.
 * \param networkMask The Ipv4Mask to extract the network.
 * \param interface The network interface index used to send packets to the
 * destination.
 * \param def Whether route should be added to default routing table
 *
 * \see Ipv4Address
 */
 Ptr<Ipv4TexcpTableEntry> AddNetworkRouteTo (Ipv4Address network, 
                                     Ipv4Mask networkMask,
                                     uint32_t interface, 
                                     struct IEPair s,
                                     DataRate r = DataRate("100Mbps"));


/**
 * \brief Get the number of individual unicast routes that have been added
 * to the routing table.
 *
 * \warning The default route counts as one of the routes.
 */
  uint32_t GetNRoutes (void);

/**
 * \brief Get a route from the static unicast routing table.
 *
 * Externally, the unicast static routing table appears simply as a table with
 * n entries.  
 *
 * \param i The index (into the routing table) of the route to retrieve.  
 * \return If route is set, a pointer to that Ipv4TexcpTableEntry is returned, otherwise
 * a zero pointer is returned.
 *
 * \see Ipv4TexcpTableEntry
 * \see Ipv4TexcpRouting::RemoveRoute
 */
  Ipv4TexcpTableEntry GetRoute (uint32_t i);

/**
 * \brief Get a metric for route from the static unicast routing table.
 *
 * \param index The index (into the routing table) of the route to retrieve.  
 * \return If route is set, the metric is returned. If not, an infinity metric (0xffffffff) is returned
 *
 */
  uint32_t GetMetric (uint32_t index);
  
/**
 * \brief Remove a route from the static unicast routing table.
 *
 * Externally, the unicast static routing table appears simply as a table with
 * n entries.  
 *
 * \param i The index (into the routing table) of the route to remove.  
 *
 * \see Ipv4TexcpTableEntry
 * \see Ipv4TexcpRouting::GetRoute
 * \see Ipv4TexcpRouting::AddRoute
 */
  void RemoveRoute (uint32_t i);

  //void LogRoutingTable (const std::list<Ipv4TexcpTableEntry*>* routeTable);
  void LogRoutingTables ();


  void AddEgressAddress (Ipv4Address eAddr);
   
  virtual void DoStart (int mode);

  void SetSplittingMode (SplittingMode mode);

  typedef std::vector<Ipv4TexcpTableEntry *> NetworkRoutes;
  typedef std::vector<Ipv4TexcpTableEntry * >::iterator NetworkRoutesI;
  typedef std::map<struct IEPair, NetworkRoutes *>::iterator PairPathsI;

 
protected:
  virtual void DoDispose (void);
                  
private:                                    
  Ipv4TexcpTableEntry* LookupTexcp (Ipv4Address dest, NetworkRoutes* routeTable);
  Ipv4TexcpTableEntry* LookupTexcpEntry (IEPair, uint32_t idx);
  uint32_t SelectRoute (Ipv4Address dest);
  struct IEPair LookupIEPair (Ipv4Address dest);
  //void SendPacket (Ptr<Packet> packet, Ptr<Socket> socket, InetSocketAddress egress);
  void RecvTexcpProbe (Ptr<Socket> socket);

  Ptr<Ipv4> m_ipv4;                                                  

  int m_agentType;
  Ipv4Address m_egressAddress;
  
  //void SetProbe (Ipv4TexcpTableEntry* path);
  Time m_updateLossInterval;//For a Reflex based calculation of Loss
  void UpdateLossStats();
  Time m_flowletTimeOut;
  Time m_probeInterval;
  Timer m_probeTimer;
  void ProbeTimerExpire ();
  Timer m_decisionTimer;
  void DecisionTimerExpire (); 

  std::list< uint32_t> m_externalInterfaces;  
  std::map< struct IEPair, NetworkRoutes*> m_iePairPaths;
  std::map< struct IEPair, Ptr<Socket> > m_pairSocket;
  std::map< struct IEPair, IntEmpiricalVariable* > m_iePairRand;

  TracedCallback<Ptr<Ipv4TexcpTableEntry> > m_traceUpdate;

  //Ptr<Ipv4FlowletClassifier> m_classifier;
  Ipv4FlowletClassifier m_classifier;

  int SelectPath(struct IEPair s, uint32_t size);

  int m_nextPathShaperID;
  int GetNextPathShaperId()
  {
    return m_nextPathShaperID++;
  };
  

  SplittingMode m_sMode;

  Callback <double, std::vector<Ipv4TexcpTableEntry*> *, double, double> m_weightUpdate;

};


}} // Namespace ns3

#endif /* IPV4_TEXCP_ROUTING_H */
